﻿using adb;
using EntityFrameworkCore.UseRowNumberForPaging;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Diagnostics;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Hosting;
using Microsoft.OpenApi.Models;
using PowerStation.AppCode;
using Swashbuckle.AspNetCore.SwaggerUI;
using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Text.Json;
using System.Xml;
using utils;
using Z.EntityFramework.Plus;

namespace PowerStation
{

    /// <summary>
    /// 
    /// </summary>
    public class Startup
    {
        /// <summary>
        /// 
        /// </summary>
        /// <param name="configuration"></param>
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
            //this.ConfigZLib();
            //provider.Mappings[".m3u8"] = "application/vnd.apple.mpegurl";
            //provider.Mappings[".ts"] = "video/mp2t";
        }
        /// <summary>
        /// 配置数据库日志
        /// </summary>
        public void ConfigZLib()
        {
            QueryCacheManager.MemoryCacheEntryOptionsFactory = () =>
            {
                var options = new Microsoft.Extensions.Caching.Memory.MemoryCacheEntryOptions() { AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(30) };
                return options;
            };
            //Action<DbCommand> action = cmd => {
            //    Console.Write("语句开始:");
            //    Console.Write(System.Environment.NewLine);
            //    for (var i = 0; i < cmd.Parameters.Count; i++)
            //    {
            //        var item = cmd.Parameters[i];
            //        Console.WriteLine($"{item.ParameterName} = {item.Value},${item.DbType}");
            //    }
            //    Console.Write(System.Environment.NewLine);
            //    Console.Write(cmd.CommandText);
            //    Console.Write(System.Environment.NewLine);
            //    Console.Write("语句结束");
            //    Console.Write(System.Environment.NewLine);
            //};
            //BatchUpdateManager.BatchUpdateBuilder = builder => {
            //    builder.Executing = action;
            //};
            //BatchDeleteManager.BatchDeleteBuilder = builder =>
            //{
            //    builder.Executing = action;
            //};
        }
        /// <summary>
        /// 
        /// </summary>
        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        /// <summary>
        /// 
        /// </summary>
        /// <param name="services"></param>
        public void ConfigureServices(IServiceCollection services)
        {
            services.Configure<FormOptions>(options =>
            {
                options.ValueLengthLimit = int.MaxValue;
                options.MultipartBodyLengthLimit = long.MaxValue; // <-- ! long.MaxValue
                options.MultipartBoundaryLengthLimit = int.MaxValue;
                options.MultipartHeadersCountLimit = int.MaxValue;
                options.MultipartHeadersLengthLimit = int.MaxValue;
               
            });
            services.AddDbContext<MyDbContext>(optionsBuilder =>
            {
                object p = optionsBuilder.UseSqlServer(this.Configuration["DBStr"], b => {
                    b.UseRowNumberForPaging();
                    b.CommandTimeout(60);
                });
                //optionsBuilder.LogTo(x =>
                //{
                //    Console.WriteLine(x);
                //}, LogLevel.Information);
                optionsBuilder.EnableSensitiveDataLogging(true);
            });
            services.AddDbContext<DeviceDbContext>(optionsBuilder =>
            {
                object p = optionsBuilder.UseSqlServer(this.Configuration["DBDeviceStr"], b => {
                    b.UseRowNumberForPaging();
                    b.CommandTimeout(60);
                });
                //optionsBuilder.LogTo(x =>
                //{
                //    Console.WriteLine(x);
                //}, LogLevel.Debug);
                optionsBuilder.EnableSensitiveDataLogging(true);
            });
            services.AddDbContext<LogDbContext>(optionsBuilder =>
            {
                object p = optionsBuilder.UseSqlServer(this.Configuration["LogStr"], b => {
                    b.UseRowNumberForPaging();
                    b.CommandTimeout(60);
                });
                //optionsBuilder.LogTo(x =>
                //{
                //    Console.WriteLine(x);
                //}, LogLevel.Information);
                optionsBuilder.EnableSensitiveDataLogging(true);
            });
            services.AddControllers().AddJsonOptions(options => {
                options.JsonSerializerOptions.Converters.Add(new DateTimeJsonConverter("yyyy-MM-ddTHH:mm:ss"));
                options.JsonSerializerOptions.Converters.Add(new DecimalConverter());
            });
            services.AddSwaggerGen(c =>
            {
                c.SwaggerDoc("v1", new OpenApiInfo() { Title = "水电站远程监测系统", Version = "版本1.0" });

                //string basePath2 = Path.GetDirectoryName(typeof(Program).Assembly.Location);
                string basePath1 = Path.GetFullPath("./xml/");

                c.IncludeXmlComments(XmlPath(basePath1), true);
                var securitySchema = new OpenApiSecurityScheme
                {
                    Description = "JWT Authorization header using the Bearer scheme. Example: \"Authorization: Bearer {token}\"",
                    Name = "Authorization",
                    In = ParameterLocation.Header,
                    Type = SecuritySchemeType.Http,
                    Scheme = "bearer",
                    Reference = new OpenApiReference
                    {
                        Type = ReferenceType.SecurityScheme,
                        Id = "Bearer"
                    }
                };

                c.AddSecurityDefinition("Bearer", securitySchema);

                var securityRequirement = new OpenApiSecurityRequirement
                {
                    { securitySchema, new[] { "Bearer" } }
                };

                c.AddSecurityRequirement(securityRequirement);
            });
            services.AddAuthorizationSetup(this.Configuration);
            services.TryAddSingleton<IHttpContextAccessor, HttpContextAccessor>();
            services.AddScoped<RankCheck, RankCheck>();
            services.AddSingleton<IMqttModel,IMqttModel>();
            services.AddCors(options =>
            {
                options.AddPolicy("Test",

                builder => builder.AllowAnyOrigin()

                .WithMethods("GET", "POST", "HEAD", "PUT", "DELETE", "OPTIONS")
                .WithHeaders("authorization", "content-type")
                );

            });
            services.AddSingleton<RedisUtil>();
        }
        //private static FileExtensionContentTypeProvider provider = new FileExtensionContentTypeProvider();
        //private static StaticFileOptions videoFile = new StaticFileOptions
        //{
        //    RequestPath = @"/live",
        //    FileProvider = new PhysicalFileProvider(@"V:\"),
        //    ContentTypeProvider = provider
        //};
        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        /// <summary>
        /// 
        /// </summary>
        /// <param name="app"></param>
        /// <param name="env"></param>
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            
            
            app.UseCalculateExecutionTime();
            if (false)//(env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseExceptionHandler(errorApp =>
                {
                    errorApp.Run(async context =>
                    {
                        context.Response.StatusCode = 500;
                        context.Response.ContentType = "application/json";
                        var ex = context.Features.Get<IExceptionHandlerPathFeature>();
                        await context.Response.WriteAsync(JsonSerializer.Serialize(ResultApi.error<object>(null, ex?.Error.Message)));
                    });
                });
                app.UseHsts();
            }
            app.UseCors("Test");
            app.UseHttpsRedirection();
            app.Use((context, next) =>
            {
                context.Request.EnableBuffering();
                return next();
            });
            app.UseRouting();

            app.UseAuthentication();
            app.UseAuthorization();
            //app.UseStaticFiles(videoFile);
            app.UseSwagger(c =>
            {
                
            });
            app.UseSwaggerUI(c =>
            {
                c.SwaggerEndpoint("v1/swagger.json", "v1");
                c.DocExpansion(DocExpansion.None);
                c.ConfigObject.PersistAuthorization = true;
                
            });
            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();
            });
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="pach"></param>
        /// <returns></returns>
        public static string XmlPath(string pach)
        {
            var savePsth = $@"{pach}swagger.xml";
            var filesPath = Directory.GetFiles($@"{pach}");
            List<XmlDocument> xmls = new List<XmlDocument>();
            foreach (string s in filesPath)
            {
                if (s.ToLower().EndsWith(".xml") && !s.ToLower().EndsWith("swagger.xml"))
                {
                    XmlDocument xml = new XmlDocument();
                    xml.Load(s);
                    xmls.Add(xml);
                }
            }
            var mainDoc = new XmlDocument();
            mainDoc.LoadXml($@"<?xml version=""1.0""?><doc><assembly><name>{Assembly.GetCallingAssembly().FullName}</name></assembly><members></members></doc>");
            var members = mainDoc.SelectSingleNode("//members"); ;

            foreach (XmlDocument item in xmls)
            {
                var membersNode = item.SelectSingleNode("//members");
                var nodes = membersNode?.SelectNodes("//member");
                if (nodes != null)
                    foreach (XmlNode node in nodes)
                    {
                        XmlNode newXml = mainDoc.ImportNode(node, true);
                        members?.AppendChild(newXml);
                    }
            }
            mainDoc.Save(savePsth);
            return savePsth;

        }
    }
}
